import pygame.gfxdraw

monkeyKey = [0]*320
monkeyKey[pygame.K_BACKSPACE] = 8
monkeyKey[pygame.K_TAB] = 9
monkeyKey[pygame.K_RETURN] = 13
monkeyKey[pygame.K_LSHIFT] = 160
monkeyKey[pygame.K_RSHIFT] = 161
monkeyKey[pygame.K_LCTRL] = 162
monkeyKey[pygame.K_RCTRL] = 163
monkeyKey[pygame.K_LALT] = 164
monkeyKey[pygame.K_RALT] = 165
monkeyKey[pygame.K_ESCAPE] = 27
monkeyKey[pygame.K_SPACE] = 32
monkeyKey[pygame.K_PAGEUP] = 33
monkeyKey[pygame.K_PAGEDOWN] = 34
monkeyKey[pygame.K_END] = 35
monkeyKey[pygame.K_HOME] = 36
monkeyKey[pygame.K_LEFT] = 37
monkeyKey[pygame.K_UP] = 38
monkeyKey[pygame.K_RIGHT] = 39
monkeyKey[pygame.K_DOWN] = 40
monkeyKey[pygame.K_INSERT] = 45
monkeyKey[pygame.K_DELETE] = 46
monkeyKey[pygame.K_0:pygame.K_9+1] = range(48, 58)
monkeyKey[pygame.K_a:pygame.K_z+1] = range(65, 91)
monkeyKey[pygame.K_KP0:pygame.K_KP9+1] = range(96, 106)
monkeyKey[pygame.K_F1:pygame.K_F12+1] = range(112, 124)
monkeyKey[pygame.K_LSUPER] = 91
monkeyKey[pygame.K_RSUPER] = 92
monkeyKey[pygame.K_KP_MULTIPLY] = 106
monkeyKey[pygame.K_KP_PLUS] = 107
monkeyKey[pygame.K_KP_DIVIDE] = 108
monkeyKey[pygame.K_KP_MINUS] = 109
monkeyKey[pygame.K_KP_PERIOD] = 110
monkeyKey[pygame.K_KP_ENTER] = 111
monkeyKey[pygame.K_BACKQUOTE] = 192
monkeyKey[pygame.K_EQUALS] = 187
monkeyKey[pygame.K_LEFTBRACKET:pygame.K_RIGHTBRACKET+1] = range(219,222)
monkeyKey[pygame.K_SEMICOLON] = 186
monkeyKey[pygame.K_QUOTE] = 222
monkeyKey[pygame.K_COMMA:pygame.K_SLASH+1] = range(188,192)

def getPolyBoundingRect(points):
	xA = []
	yA = []
	
	for p in points:
		xA.append(p[0])
		yA.append(p[1])
	
	x = min(xA)
	y = min(yA)
	w = max(xA)-x
	h = max(yA)-y
	
	return (x, y, w, h)

def dist2d(p0, p1):
	return math.sqrt((p1[0]-p0[0])*(p1[0]-p0[0]) + (p1[1]-p0[1])*(p1[1]-p0[1]))

import time

FPS_EVENT = USEREVENT+1
pygame.time.set_timer(FPS_EVENT, 1000)

class gxtkGame (object):
	app = None
	screen = None
	
	background = None
	clock = None
	
	frames = 0
	
	def __init__(self):
		pygame.mixer.pre_init(44100,-16,2,2048)
		pygame.init()
		
		pygame.display.set_caption(CFG_PYTHON_WINDOW_TITLE)
		self.clock = pygame.time.Clock()
		self.frames = 0
		
		pygame.event.set_allowed(None)
		pygame.event.set_allowed(QUIT)
		pygame.event.set_allowed(range(KEYDOWN, JOYBUTTONUP+1))
		pygame.event.set_allowed(FPS_EVENT)
		pass
	
	def start(self):
		if self.app != None:
			self.app.InvokeOnCreate()

			while True:
				
				self.frames += 1
				#mill = self.clock.tick(60)
                    
				for event in pygame.event.get():
					if event.type == QUIT:
						pygame.quit()
						sys.exit()
					
					if event.type == FPS_EVENT:
						self.app.fps = self.frames
						self.frames = 0
						
					if event.type >= pygame.KEYDOWN and event.type <= pygame.JOYBUTTONUP:
						self.app.ProcessInput(event)
						
				self.app.Update()
				
				self.app.UpdateInput()
				self.app.Render()
				
	
game = gxtkGame()	

class gxtkApp (object):
	graphics = None
	_input = None
	audio = None
	
	updateRate = 0
	nextUpdate = 0.0
	updatePeriod = 0.0
	
	startMillis = 0
	fps = 0
	
	suspended = False
	
	hatButtonL = 8
	hatButtonR = 10
	hatButtonU = 9
	hatButtonD = 11
	
	def __init__(self):
		game.app = self
		
		self.graphics = gxtkGraphics()
		self._input = gxtkInput()
		self.audio = gxtkAudio()
		self.fps = 0
		self.startMillis = pygame.time.get_ticks()
		self.hatButtonL = 8
		self.hatButtonR = 10
		self.hatButtonU = 9
		self.hatButtonD = 11
		pass
	
	def GraphicsDevice(self):
		return self.graphics
		
	def InputDevice(self):
		return self._input
		
	def AudioDevice(self):
		return self.audio
		
	def AppTitle(self):
		return "gxtkApp"
		
	def SetUpdateRate(self, hertz):
		self.updateRate = hertz
		
		if self.updateRate != 0:
			self.updatePeriod = 1000.0/float(hertz)
		else:
			self.updatePeriod = 1
			
		self.nextUpdate=float(pygame.time.get_ticks()) + self.updatePeriod
		
		#pygame.time.set_timer(UPDATE_EVENT, int(self.updatePeriod))
			
	def MilliSecs(self):
		return pygame.time.get_ticks() - self.startMillis
	
	def Update(self):
		updates = 0
		self.InvokeOnUpdate()
		return
		
		"""while True:
			self.nextUpdate += self.updatePeriod
			self.InvokeOnUpdate()
			if self.updateRate == 0:
				break
			
			if self.nextUpdate > float(pygame.time.get_ticks()):
				break
				
			updates += 1
			if updates == 7:
				self.nextUpdate = float(pygame.time.get_ticks())
				break"""
		
	def ProcessInput(self, ev):
		if ev.type == pygame.KEYDOWN or ev.type == pygame.KEYUP:
			if ev.type == pygame.KEYDOWN and ev.unicode != "":
				self._input.AddChar(ev.unicode)
			self._input.OnKey(monkeyKey[ev.key], ev.type==pygame.KEYDOWN)
		elif ev.type == pygame.MOUSEMOTION:
			self._input.OnMouseMove(ev.pos, ev.rel)
		elif ev.type == pygame.MOUSEBUTTONDOWN or ev.type == pygame.MOUSEBUTTONUP:
				self._input.OnMouseButton(ev.button, ev.type==pygame.MOUSEBUTTONDOWN)
		elif ev.type == JOYBUTTONDOWN or ev.type == JOYBUTTONUP:
			if ev.button < 8:
				self._input.OnKey(self._input.joyToKey(ev.joy, ev.button), ev.type==JOYBUTTONDOWN)
			else:
				self._input.OnKey(self._input.joyToKey(ev.joy, ev.button+4), ev.type==JOYBUTTONDOWN)
		elif ev.type == JOYHATMOTION:
			self._input.OnKey(self._input.joyToKey(ev.joy, self.hatButtonL), ev.value[0]==-1)
			self._input.OnKey(self._input.joyToKey(ev.joy, self.hatButtonR), ev.value[0]==1)
			self._input.OnKey(self._input.joyToKey(ev.joy, self.hatButtonU), ev.value[1]==1)
			self._input.OnKey(self._input.joyToKey(ev.joy, self.hatButtonD), ev.value[1]==-1)
		elif ev.type == JOYAXISMOTION:
			self._input.OnJoyMotion(ev)

	def UpdateInput(self):
		self._input.Update()
		
	def Render(self):
		pygame.display.set_caption(CFG_PYTHON_WINDOW_TITLE + " FPS: "+str(self.fps))
		self.graphics.BeginRender()
		self.InvokeOnRender()
		self.graphics.EndRender()
		
	def InvokeOnCreate(self):
		self.OnCreate()
		
	def InvokeOnUpdate(self):
		self.OnUpdate()
		
	def InvokeOnRender(self):
		self.OnRender()
		
	def OnCreate(self):
		pass
		
	def OnRender(self):
		pass
		
	def OnUpdate(self):
		pass
	
	def LoadString(self, fileName):
		f = open("data/"+fileName, 'r')
		return f.read()
		pass

    	
class gxtkGraphics (object):
	screen = None
	screenBack = None
	background = None
	renderSurface = None
	
	color = None
	clearColor = None
	alpha = None
	pyColor = None
	
	tformed = None
	ix = iy = jx = jy = tx = ty = None
	blend = None
	scissorRect = None
	
	def __init__(self):
		self.screen = pygame.display.set_mode((int(CFG_PYTHON_WINDOW_WIDTH), int(CFG_PYTHON_WINDOW_HEIGHT)), SRCALPHA, 32)
		
		self.background = pygame.Surface(self.screen.get_size())
		self.background = self.background.convert()
		self.background.fill((33, 33, 33))
		self.clearColor = (33, 33, 33)
		
		self.renderSurface = pygame.Surface(self.screen.get_size(), SRCALPHA)
		
		#self.screen = pygame.display.get_surface().convert_alpha()
		
		self.color = (255, 255, 255)
		self.alpha = 1.0
		self.pyColor = pygame.Color(255, 255, 255, 255)
		self.tformed = False
		self.ix = self.iy = self.jx = self.jy = self.tx = self.iy = 0.0
		self.scissorRect = (0.0, 0.0, self.Width(), self.Height())
		
		
	def BeginRender(self):
		self.screenBack = self.screen
		#self.screen = self.renderSurface
		#self.screen.blit(self.background, (0,0))
		#self.renderSurface.lock()
		pass
		
	def EndRender(self):
		#self.screen.blit(self.screen, (0,0))
		#self.screen = self.screenBack
		#self.renderSurface.unlock()
		#self.screen.blit(self.renderSurface, (0,0))
		pygame.display.update()
	
	def Mode(self):
		return 1
		
	def Width(self):
		return self.screen.get_size()[0]
	
	def Height(self):
		return self.screen.get_size()[1]
		
	def Loaded(self):
		return 1
		
	def SetColor(self, r, g, b):
		self.pyColor.r = int(r)
		self.pyColor.g = int(g)
		self.pyColor.b = int(b)
		
	def SetAlpha(self, a):
		self.pyColor.a = int(a*255)
		#self.screen.set_alpha(self.pyColor.a)
		
	def SetBlend(self, blend):
		self.blend = blend
		
	def SetScissor(self, x, y, w, h):
		self.screen.set_clip((x, y, w, h))
		
	def SetMatrix(self, ix, iy, jx, jy, tx, ty):
		self.tformed = (ix != 1 or iy != 0 or jx != 0 or jy != 1 or tx != 0 or ty != 0)
		self.ix = ix
		self.iy = iy
		self.jx = jx
		self.jy = jy
		self.tx = tx
		self.ty = ty
		
	def LoadSurface(self, path):
		image = pygame.image.load("data/"+path).convert_alpha()
		if image:
			return gxtkSurface(image, self)
		return None

	def Cls(self, r, g, b):
		self.screen.fill((r, g, b))
		
	def DrawPySurface(self, surface, x, y):
		x0=x
		w = surface.get_width()
		h = surface.get_height()
		x1=x+w
		x2=x+w
		x3=x
		y0=y
		y1=y
		y2=y+h
		y3=y+h
		tempsurf = surface.copy()
		
		if self.tformed:
			tx0=x0
			tx1=x1
			tx2=x2
			tx3=x3
			x0=tx0 * self.ix + y0 * self.jx + self.tx
			y0=tx0 * self.iy + y0 * self.jy + self.ty
			x1=tx1 * self.ix + y1 * self.jx + self.tx
			y1=tx1 * self.iy + y1 * self.jy + self.ty
			x2=tx2 * self.ix + y2 * self.jx + self.tx
			y2=tx2 * self.iy + y2 * self.jy + self.ty
			x3=tx3 * self.ix + y3 * self.jx + self.tx
			y3=tx3 * self.iy + y3 * self.jy + self.ty
			ang = 0-math.degrees(math.atan2((y1-y0),(x1-x0)))
			xScale = dist2d((x0,y0),(x1,y1))/w
			yScale = dist2d((x0,y0),(x3,y3))/h
			if xScale != 1.0 or yScale != 1.0:
				tempsurf = pygame.transform.scale(tempsurf, (int(w*xScale), int(h*yScale)))
				
			tempsurf = pygame.transform.rotate(tempsurf, ang)
			bndRect = getPolyBoundingRect(((x0,y0),(x1,y1),(x2,y2),(x3,y3)))
			x = bndRect[0]
			y = bndRect[1]
		
		if (self.pyColor.r, self.pyColor.g, self.pyColor.b) != (255,255,255):
			tempsurf.fill(self.pyColor, None, BLEND_MULT)
			pass

		if self.pyColor.a != 255:
			tempsurf2 = tempsurf
			w2 = tempsurf2.get_width()
			h2 = tempsurf2.get_height()+1
			tempsurf = pygame.Surface((w2, h2)).convert()
			tempsurf.blit(self.screen, (-x, -y))
			tempsurf.blit(tempsurf2, (0, 0))
			tempsurf.set_alpha(self.pyColor.a)
			
		self.screen.blit(tempsurf, (x,y))
		
	def DrawSurface(self, surf, x, y):
		self.DrawPySurface(surf.image, x, y)
		
	def DrawSurface2(self, surf, x, y, sx, sy, sw, sh):
		self.DrawPySurface(surf.image.subsurface((sx, sy, sw, sh)), x, y)
		#self.screen.blit(surf.image, (x, y), (sx, sy, sw, sh))

	def DrawRect(self, x, y, w, h):
		x0=x
		x1=x+w
		x2=x+w
		x3=x
		y0=y
		y1=y
		y2=y+h
		y3=y+h
	
		if self.tformed:
			tx0=x0
			tx1=x1
			tx2=x2
			tx3=x3
			x0=tx0 * self.ix + y0 * self.jx + self.tx
			y0=tx0 * self.iy + y0 * self.jy + self.ty
			x1=tx1 * self.ix + y1 * self.jx + self.tx
			y1=tx1 * self.iy + y1 * self.jy + self.ty
			x2=tx2 * self.ix + y2 * self.jx + self.tx
			y2=tx2 * self.iy + y2 * self.jy + self.ty
			x3=tx3 * self.ix + y3 * self.jx + self.tx
			y3=tx3 * self.iy + y3 * self.jy + self.ty
		pygame.gfxdraw.filled_polygon(self.screen, ((x0,y0),(x1,y1),(x2,y2),(x3,y3)), self.pyColor)

		
	def DrawPoly(self, flist):
		a = []
		for f in range(0, len(flist)-1, 2):
			px = flist[f]
			py = flist[f+1]
			if self.tformed:
				ppx = px
				px=ppx * self.ix + py * self.jx + self.tx
				py=ppx * self.iy + py * self.jy + self.ty
			a.append((px, py))
		pygame.gfxdraw.filled_polygon(self.screen, a, self.pyColor)
		
	def DrawLine(self, x1, y1, x2, y2):
		if self.tformed:
			x1_t=x1 * self.ix + y1 * self.jx + self.tx;
			y1_t=x1 * self.iy + y1 * self.jy + self.ty;
			x2_t=x2 * self.ix + y2 * self.jx + self.tx;
			y2_t=x2 * self.iy + y2 * self.jy + self.ty;		
			pygame.gfxdraw.line(self.screen, int(x1_t), int(y1_t), int(x2_t), int(y2_t), self.pyColor)
		else:
			pygame.gfxdraw.line(self.screen, int(x1), int(y1), int(x2), int(y2), self.pyColor)
			
	def DrawOval(self, x, y, w, h):
		if self.tformed:
			px=x
			x = px * self.ix + y * self.jx + self.tx
			y = px * self.iy + y * self.jy + self.ty
		pygame.gfxdraw.filled_ellipse(self.screen, int(x), int(y), int(w/2), int(h/2), self.pyColor)

	def DrawPoint(self, x, y):
		if self.tformed:
			px=x
			x=px * self.ix + y * self.jx + self.tx
			y=px * self.iy + y * self.jy + self.ty
		pygame.gfxdraw.pixel(self.screen, int(x), int(y), self.pyColor)
		
class gxtkSurface (object):
	image = None
	graphics = None
	
	def __init__(self, image, graphics):
		self.image = image
		self.graphics = graphics

	def Discard(self):
		self.image = None
		return 0
		
	def Width(self):
		return self.image.get_width()
		
	def Height(self):
		return self.image.get_height()
		
	def Loaded(self):
		return 1


class gxtkInput (object):
	keyStates = None
	keyChanges = None
	mousePos = None
	mouseRel = None
	shift = False
	
	curChars = []
	charPos = 0
	
	joyPos = []
	
	def __init__(self):
		self.keyChanges = []
		self.keyStates = [0]*512
		self.mousePos = (0, 0)
		self.mouseRel = (0, 0)
		self.mouseStates = [False]*10
		self.joyPos = [0.0]*64
		
		pygame.key.set_repeat(500, 50)
		
		for i in range(4):
			try:
				pygame.joystick.Joystick(i).init()
			except:
				pass


	def Update(self):
		del self.curChars[:]
		self.charPos = 0
		pass
			
	def OnKey(self, key, state):
		if state:
			self.keyStates[key] = 2
		else:
			self.keyStates[key] = 0

	def AddChar(self, char):
		keyChar = ord(char)
		if keyChar != 0:
			self.curChars.append(keyChar)
		
	def OnMouseMove(self, pos, rel):
		self.mousePos = pos
		self.mouseRel = rel
		
	def OnMouseButton(self, button, state):
		self.keyStates[button] = state
		self.keyStates[button+383] = state
		
	def KeyDown(self, key):
		if key == 16:
			return self.ShiftDown()
		else:
			return self.keyStates[key] > 0
		
	def KeyHit(self, key):
		if key == 16:
			return self.ShiftHit()
		else:			
			if self.keyStates[key] > 1:
				self.keyStates[key] -= 1
				return 1
			return 0	
	
	def GetChar(self):
		if self.charPos < len(self.curChars):
			self.charPos += 1
			return self.curChars[self.charPos-1]
		return 0

	def MouseX(self):
		return self.mousePos[0]

	def MouseY(self):
		return self.mousePos[1]
		
	def TouchX(self, t):
		return self.mousePos[0]

	def TouchY(self, t):
		return self.mousePos[1]
		
	def OnJoyMotion(self, ev):
		self.joyPos[ev.joy*16 + ev.axis] = ev.value
		
	def JoyX(self, joyinfo):
		joy = joyinfo / 16
		index = joyinfo % 16
		return self.CleanAxis(self.joyPos[joy + index*3])
		
	def JoyY(self, joyinfo):
		joy = joyinfo / 16
		index = joyinfo % 16
		return self.CleanAxis(self.joyPos[joy + 1 + index*3])
		
	def JoyZ(self, joyinfo):
		joy = joyinfo / 16
		index = joyinfo % 16
		return self.CleanAxis(self.joyPos[joy + 2 + index*3])

	def CleanAxis(self, pos):
		abspos = abs(pos)
		if abspos > 1.0:
			return int(pos)
		elif abspos <= 0.1:
			return 0
		return pos
		
	def AccelX(self):
		return 0
		
	def AccelY(self):
		return 0
		
	def AccelZ(self):
		return 0
		
	def TwoKeyDown(self, key1, key2):
		return self.keyStates[key1] > 0 or self.keyStates[key2] > 0
		
	def TwoKeyHit(self, key1, key2):
		hit = False
		if self.keyStates[key1] > 1:
			self.keyStates[key1] -= 1
			hit = True
		if self.keyStates[key2] > 1:
			self.keyStates[key2] -= 1
			hit = True
		
		if hit:
			return 1
		else:
			return 0
				
	def SetKeyboardEnabled(self, torf):
		pass
	
	def joyToKey(self, joy, button):
		return button | joy << 4 | 0x100
	
	def keyToChar(self, key):
		if key == 8 or key == 9 or key == 13 or key == 27 or key == 32:
			return key
		elif (key > 32 and key < 41) or key == 45:
			return key | 0x10000
		elif key == 46:
			return 127
		elif key >= 48 and key <= 57 and not self.TwoKeyDown(160,161): # Left and right shifts
			return key
		elif key >= 65 and key <= 90 and not self.TwoKeyDown(160,161):
			return key+32
		elif key >= 65 and key <= 90 and self.TwoKeyDown(160,161):
			return key	
		else:
			return 0
        
class gxtkChannel (object):
	pass

class gxtkAudio (object):
	pass

class gxtkSample (object):
	pass
